<template xmlns="http://www.w3.org/1999/html">
  <div class="sea-file-picker">
    <div v-show="canUpload">
      <div @click="$refs.input.click()">
        <input type="file" ref="input" :accept="accept" style="display: none" @change="appendFile">
        <el-button size="small" type="primary" :loading="loading">点击上传</el-button>
      </div>
    </div>
    <div v-for="(item, idx) in fileList" :key="idx" class="sea-file-picker-item">
      <a style="margin-right: 16px"><i class="file-o"></i> {{ item.name || '文件' }}</a>
      <span class="sea-file-picker-remove" @click="removeFile(idx)"><i class="fa fa-remove"></i></span>
    </div>
  </div>
</template>
<script>
/* eslint-disable */
import Layers from "@/lang/layers";

/**
 * 文件上传接口
 *
 * @param file {File}
 */
const default_upload = (file) => {
    return Promise.resolve({name: file.name, size: file.size, ref: file});
}

/**
 * 文件移除接口
 *
 * @param item
 * @returns {Promise<void>}
 */
const default_remove = (item) => {
    return Promise.resolve();
}

/**
 * 图片上传
 *
 * 图片上传组件，因为图片涉及到预览的问题，相对于其它文件，图片使用频率也是最高的，
 * 因此单独封装，方便后期功能扩展。
 *
 * 注意这个不是根据 el-upload 封装的，虽然 el-upload 的功能很强，但是封装的内容太多，
 * 使用的时候，如果参数过多，Vue 数据联动，很容易发生界面跳动闪烁。
 *
 * 这个组件代码非常简单，核心代码包含注释只有三百多行，大幅度减轻代码设计，界面响应流畅。
 */
export default {
    name: "SeaFileUploader"
    , components: {}
    , props: {
        value: {type: Array, default: Layers.array}
        // 文件数量上限
        , limit: {type: Number, default: 1}
        // 可接受的文件类型
        , accept: {type: String, default: '*'}
        // 上传配置选择
        , plugin: {type: String, default: 'image'}
        // 文字提示
        , placeholder: {type: String, default: ''}

        // 文件上传函数，也可以等到最后统一上传
        , upload: {type: Function, default: default_upload}
        // 文件上传函数，也可以等到最后统一上传
        , remove: {type: Function, default: default_remove}
    }, model: {
        //需要定义哪一个props可以用v-model绑定属性
        prop: 'value',
        //声明一个事件，调用之后，就会改变父级容器的值
        event: 'handlerValueChange'
    }, data() {
        return {
            // 值模型，任何时候都不允许为空，避免VUE联动失效
            valueModel: undefined
            // 文件列表
            , fileList: []
            // 数据上传中
            , loading: false
        }
    }, computed: {
        canUpload: function () {
            return this.fileList.length < this.limit;
        }
    }, watch: {
        value: {
            handler: function (val) {
                this.fileList = val;
            }
        }
    }, mounted() {
        this.fileList = this.value;
    }, methods: {

        /**
         * 值改变事件
         */
        onChange: function (val) {
            //侦听到setter()事件，将值传递回父级组件
            this.$emit('handlerValueChange', val);
            this.$emit('change', val);
        }
        /**
         * 移除图片
         *
         * @param idx 文件序号
         */
        , removeFile: function (idx) {
            let list = this.fileList;
            let item = list[idx];
            list.splice(idx, 1);

            this.onChange(this.fileList);

            // 即使移除失败，也不能影响主要业务
            this.remove(item);
        }

        /**
         * 用户选择了新的文件
         *
         * @param event change事件对象实例
         */
        , appendFile(event) {
            if (this.loading === true) {
                Layers.warn('点击过快');
                return;
            }

            try {
                this.loading = true;
                let files = event.target.files;

                let ret = Layers.sequentialPromise((resolve, i) => {
                    this.upload(files[i]).then(item => {
                        this.fileList.push(item);
                        resolve();
                    })
                }, 0, files.length);

                ret.then(() => {
                    this.onChange(this.fileList);

                    // 完成所有文件的提交，关闭加载条
                    this.loading = false
                    event.target.value = '';
                });
            } catch (e) {
                console.error(e);
                // 触发异常，关闭加载条
                this.loading = false
                event.target.value = '';
            }
        }
    }
}
</script>
